// 3. 多态
/**
 * 1. 静态多态、静态链接、早绑定
 * 2. 多态的作用
 *      多个派生类可以有，带有相同函数名，甚至参数相同的不同功能的函数
 * 3. virtual 关键字
 * 4. #41形成多态的三个必要条件
 *      + 必须存在继承关系
 *      + 继承关系必须有同名虚函数（其中虚函数时在基类中使用关键字Virtual 声明的函数，在派生类中重新定义基类中定义的虚函数时，会告诉编译器不要静态链接到该函数）
 *      + 存在基类类型的指针或者引用，通过该指针或引用调用虚函数
 * 5. 虚函数
 *        动态链接、后期绑定
 * 6. 纯虚函数
 *      语法:
 *         virtual return_type func() = 0;
 *         注意函数主体部分换成 =0
 *      抽象类：
 *          有纯虚函数的类是抽象类，无法被实例化。
 * 
 * 扩展（#xx1 末尾补1）：
 *  1. 只声明不定义的虚函数也是纯虚函数。普通成员函数只声明不定义会报错，虚函数不会。注意：这样写派生类必须重写该函数，不然会报错。
 *  2. 虚函数表(VTABLE)的概念
 *  3. #311 final关键字使用 
 *          - final基类的虚/纯虚函数在派生类中无法被重写 (final不能修饰非虚函数)
 *          - final类无法被继承
*/
#include <iostream>
#define __mark 311

#if __mark == 41
class A
{
private:
  int a;

public:
  A() : a(0)
  {
    // std::cout << "A()" << std::endl;
  }
  A(int _a) : a(_a)
  {
    // std::cout << "A(int)" << std::endl;
  }
  virtual void print()
  {
    std::cout << "class A print()..." << std::endl;
  }
};

class B : public A
{
private:
  int b;

public:
  // B() : A(), b(0) {}
  B() : b(0) {}
  B(int _a) : A(_a), b(0) {}
  B(int _a, int _b) : A(_a), b(_b) {}
  void print()
  {
    std::cout << "class B print()..." << std::endl;
  }
};
class C : public A
{
private:
  int c;

public:
  C() : A(), c(0) {}
  C(int _a) : A(_a), c(0) {}
  C(int _a, int _c) : A(_a), c(_c) {}
};
int main()
{
  A a1(1);
  // B b1;
  B b1(2);
  C c1(3);
  A *a_p_b1 = &b1;
  A *a_p_c1 = &c1;
  a_p_b1->print();
  a_p_c1->print();

  A &a_r_b1 = b1;
  A &a_r_c1 = c1;
  a_r_b1.print();
  a_r_c1.print();

  printf("-----------end--------------\n");
  return 0;
}
#elif __mark == 311
// #311. final关键字使用
/**
 * 禁止类被继承
 * final 禁止类虚函数重写
*/

// 无法修饰普通函数
// final void fun1()
// {
//   std::cout << "::fun1()..." << std::endl;
// }

// 修饰基类后，被继承时会终止程序
// class A final
class A
{
private:
  int a;

public:
  A() : a(0) {}
  A(int _a) : a(_a) {}

public:
  // virtual void fun1() final
  // {
  //   std::cout << "class A fun1()..." << std::endl;
  // }

  virtual void fun1() final = 0;
};
class B : public A
{
private:
  int b;

public:
  B() : A(), b(0) {}
  B(int _a) : A(_a), b(0) {}
  B(int _a, int _b) : A(_a), b(_b) {}
  void fun1()
  {
    std::cout << "class B fun1()..." << std::endl;
  }
};
int main(void)
{
  B b1(1, 2);
  A *pa_b1 = &b1;
  pa_b1->fun1();
  printf("--------------end-----------------\n");
  return 0;
}
#elif __mark == 2
int main()
{
  printf("-----------end--------------\n");
  return 0;
}
#endif;